[Chapter 22] 22.3 tcpwrapper
Author: Simson Garfinkel & Gene Spafford
Date: 1999-02-04T00:17:09Z

#

| Chapter 22 Wrappers and Proxies |

## 22.3 tcpwrapper

The tcpwrapper program, written by Wietse Venema, is an easy-to-use utility that you can use for logging and intercepting TCP services that are started by inetd.

### 22.3.1 Getting tcpwrapper

The `tcpwrapper` program can be downloaded from the Internet using anonymous FTP. The path is:

ftp://ftp.win.tue.nl/pub/security/tcp_wrapper_XXX.tar.gz

Where XXX is the current version number. The file that you FTP will be a tar archive compressed with gunzip (often called gzip). While you are connected to the computer ftp.win.tue.nl, you might want to pick up Venema's portmapper replacement.

Another good place to look for tcpwrapper is:

ftp://coast.cs.purdue.edu/pub/tools/tcp_wrappers

While you are connected to the coast.cs.purdue.edu machine, you can find scores of other nifty security tools and papers, so don't connect if you only have a few minutes to spare!

The tcpwrapper program is shipped standard with only a few operating systems such as BSD/OS. (It is shipped standard with Linux but is rarely configured properly.) We hope that this standard will change in the future.

### 22.3.2 What tcpwrapper Does

The `tcpwrapper` program gives the system administrator a high degree of control over incoming TCP connections. The program is started by `inetd` after a remote host connects to your computer; then `tcpwrapper` does one or more of the following:

- Optionally sends a "banner" to the connecting client. Banners are useful for displaying legal messages or advisories.

- Performs a double-reverse lookup of the IP address, making sure that the DNS[5] entries for the IP address and hostname match. If they do not, this fact is logged. (By default, `tcpwrapper` is compiled with the -DPARANOID option, so the program will automatically drop the incoming connection if the two do not match, under the assumption that something somewhere is being hacked.)

  > [5] Domain Name Service, the distributed service that maps IP numbers to hostnames, and vice versa.

- Compares the incoming hostname and requested service with an access control list, to see if this host or this combination of host and service has been explicitly denied. If either is denied, `tcpwrapper` drops the connection.

- Uses the ident protocol (RFC 1413)[6] to determine the username associated with the incoming connection.

  > [6] RFC 1413 superseded RFC 931, but the `define` in the code has not changed.

- Logs the results with `syslog`. (For further information, see Chapter 10, Auditing and Logging.)

- Optionally runs a command. (For example, you can have `tcpwrapper` run `finger`, to get a list of users on a computer that is trying to contact yours.)

- Passes control of the connection to the "real" network daemon, or passes control to some other program that can take further action.

- Transfers to a "jail" or "faux" environment where you study the user's actions.[7]

  > [7] We won't describe this approach further. It requires some significant technical sophistication to get right, is of limited value in most environments, and may pose some potentially significant legal problems. For further information on hacker jails, see Firewalls and Internet Security by Bill Cheswick and Steve Bellovin.

The `tcpwrapper` thus gives you a way to add logging to services that are not normally logged, such as `finger` and `systat`. It also allows you to substitute different versions of a service daemon depending on the calling host - or to reject the connection without providing any server at all.

### 22.3.3 Understanding Access Control

The `tcpwrapper` system has a simple but powerful language and a pair of configuration files that allow you to specify whether or not incoming connections should be accepted. The files are /etc/hosts.allow and /etc/hosts.deny. When an incoming connection is handed to `tcpwrapper`, the program applies the following rules:

1. The file /etc/hosts.allow is searched to see if this (host, protocol) pair should be allowed.

2. If no match if found, the file /etc/hosts.deny is searched to see if this (host, protocol) pair should be denied.

3. If no match is found, the connection is allowed.

Each line in the /etc/hosts.allow and/etc/hosts.deny file has the following format:

>     daemon_list : client_host_list [: shell_command]

Where:

daemon_list

  Specifies the command name (argv[0]) of a list of TCP daemons (e.g., `telnetd`). The reserved keyword "ALL" matches all daemons; you can also use the "EXCEPT" operator (e.g., "ALL EXCEPT in.ftpd").

client_host_list

  Specifies the hostname or IP address of the incoming connection. You can also use the format username@hostname to specify a particular user on a remote computer, although the remote computer must implement the `ident` protocol.[8] The keyword ALL matches all clients; for a full list of keywords, see Table 22.1.

  > [8] And as we noted in the discussion of `ident`, the identification returned is not something that can always be believed.

shell_command

  Specifies a command that should be executed if the daemon_list and client_host_list are matched. A limited amount of token expansion is available within the shell command; see Table 22.2 for a list of the tokens that are available.

Table 22.1: Special tcpwrapper Hosts
Hostname as it Appears in the File /etc/hosts.allow or /etc/hosts.deny | Has This Effect:
--- | ---
ALL | Matches all hosts.
KNOWN | Matches any IP address that has a corresponding hostname; also matches usernames when the `ident` service is available.
LOCAL | Matches any host that does not have a period (.) in its name.
PARANOID | Matches any host for which double-reverse hostname/IP address translation does not match.
UNKNOWN | Matches any IP address that does not have a corresponding hostname. Also matches usernames when `ident` service is not available.
.subdomain.domain | If the hostname begins with a period (.), the hostname will match any host whose hostname ends with the hostname (in this case, ".subdomain.domain").
iii. iii.jjj. iii.jjj.kkk. iii.jjj.kkk.lll. (e.g.,18. or 204.17.195.) | If the hostname ends with a period (.), the hostname is interpreted as the beginning of an IP address. The string "18." will match any host with an IP addresses 18.0.0.1 through 18.255.255.254. The string "204.17.195." will match any host with an IP addresses 204.17.195.1 through 204.17.195.254.
a pattern EXCEPT another pattern | Matches any host that is matched by a pattern except those that also match another pattern.[9]

> [9] The EXCEPT operator may also be used for specifying an Internet service.

Table 22.2: Token Expansion Available for the tcpwrapper Shell Command
Token | Mnemonic | Expands to:
--- | --- | ---
%a | address | The IP address of the client.
%A | address | The IP address of the server.
%c | client info | username@hostname (if username is available); otherwise, only hostname or IP address.
%d | daemon name | The name of the daemon (`argv`[0]).
%h | hostname | The hostname of the client. (IP address if hostname is unavailable.)
%H | hostname | The hostname of the server. (IP address if hostname is unavailable.)
%p | process | The Process ID of the daemon process.
%s | server info. | daemon@host.
%u | user | The client username (or unknown)
%% | percent | Expands to the "%" character.

> NOTE: The `tcpwrapper` is vulnerable to IP spoofing because it uses IP addresses for authentication. The `tcpwrapper` also provides only limited support for UDP servers, because once the server is launched, it will continue to accept packets over the network, even if those packets come from "blocked" hosts.

### 22.3.4 Installing tcpwrapper

`tcpwrapper` is a powerful program that can seriously mess up your computer if it is not properly installed. It has many configuration options that are set at compile time. Therefore, before you start compiling or installing the program, read all of the documentation.

Briefly, here is what the documentation will tell you to do:

1. You need to decide where to place the `tcpwrapper` program and where to place your "real" network daemons. The documentation will give you a choice. Your first option is to name the `tcpwrapper` program something innocuous, like /usr/local/etc/tcpd, leave the "real" network daemons in their original locations, and modify the inetd configuration file /etc/inetd.conf. Alternatively, you can move the network daemons (such as /usr/sbin/in.fingerd) to another location (such as /usr/sbin.real/in.fingerd), place the tcpwrapper in the location that the daemon formerly occupied, and leave the file /etc/inetd.conf as is.

   We recommend that you leave your executable programs where they currently are, and modify the /etc/inetd.conf file. The reason for this recommendation is that having changes in your system configuration clearly indicated in your system configuration files is less confusing than changing the names and/or the locations of your distributed system programs. In the long run, this option is much more maintainable. This is especially important if vendor patches expect to find the binary where it was originally stored, and overwrite it.

2. Having followed our advice and decided that you will modify your /etc/inetd.conf file, make a copy of the file, in case you make any mistakes later:

   >     # cp /etc/inetd.conf /etc/inetd.conf.DIST
   >     #

3. Edit `tcpwrapper`'s Makefile so that the variable REAL_DAEMON_DIR reflects where your operating system places its network daemons. Check the other options in the Makefile to be sure they are appropriate to your needs.

4. Compile `tcpwrapper`.

5. Read the `tcpwrapper` man pages host_access and host_options. These files define the tcpwrapper host access-control language that is used by the files /etc/hosts.allow and /etc/hosts.deny.

   You may wish to start off with a relatively simple set of rules - for example, allowing all services to all machines except for a small group that have been known to cause problems. But you may wish to also enable complete logging, so that you can see if particular services or sites warrant further attention.

6. Create your /etc/hosts.allow and/etc/hosts.deny files. If you wish to allow all TCP servers through, you do not need to create these files at all (`tcpwrapper` will default to rule #3, which is to pass through all connections). If you wish to deny service from a specific machine, such as pirate.net, you could simply create a single /etc/hosts.deny file, like this:

   >     #
   >     # /etc/hosts.deny
   >     #
   >     all : pirate.net

   Alternatively, you could use the following /etc/hosts.deny, which would finger the computer pirate.net and email the result to you (security@machine.com), whenever somebody from that network tries to initiate any connection to your machine. Note that this example uses the safe_finger command that comes with `tcpwrapper`; this version of the `finger` command will remove control characters or other nasty data that might be returned from a `finger` server running on a remote machine, as well as limit the total amount of data received:[10]

   > [10] The `safe_finger` program is a replacement for your system's `finger` program, which automatically filters out dangerous characters allowed through by the standard versions of finger. If you don't think that your standard UNIX `finger` program should allow data-driven attacks, you might wish to send a letter to your UNIX vendor.

   >     #
   >     # /etc/hosts.deny with more logging!
   >     #
   >     all EXCEPT in.fingerd : pirate.net : (/usr/local/bin/safe_finger -l @%h | \
   >     						/bin/mailx -s %d-%h security@machine.com) &

   Note that the /etc/hosts.deny file allows continuation lines by using the backslash (\) character.

   The `finger` command is run for all services except in.fingerd; this restriction prevents a "feedback loop" in which a `finger` on one computer triggers a `finger` on a second computer, and vice versa. Also note that the `finger` command is run in the background; this mode prevents `tcpwrapper` from waiting until the safe_finger command completes.

7. Check out your /etc/syslog.conf file to make sure that `tcpwrapper`'s events will be logged! By default, `tcpwrapper` will log with LOG_ERR if a program cannot be launched, LOG_WARNING if a connection is rejected, and LOG_INFO if a connection is accepted. The logging service is LOG_MAIL, but you can change it by editing the program's Makefile.

8. If you make any changes to the `syslog` configuration file, restart `syslog` with the command:

   >     		# kill -1 `cat /etc/syslog.pid`

9. Edit your /etc/inetd.conf file so that the `tcpwrapper` program is invoked by `inetd` for each service that you wish to log and control.

   Modifying the /etc/inetd.conf file is easy: simply change the filename of each program to the full pathname of the `tcpwrapper` program, and edit the command name of each program so that it is the complete pathname of the original network daemon.

   For example, if you have a line in your original /etc/inetd.conf file that says this:

   >     finger   stream tcp nowait nobody /usr/etc/fingerd fingerd

   Change it to this:

   >     finger  stream tcp nowait nobody /usr/local/bin/tcpd /usr/etc/fingerd

   You may need to send a signal to the `inetd` daemon, or restart it, to get it to note the new configuration you have added.

10. Test to make sure that everything works! For example, try doing a `finger` of your computer; does a message get written into your system's log files? If not, check to make sure that `inetd` is starting the `tcpwrapper`, that `tcpwrapper` can access its configuration files, and that the `syslog` system is set up to do something with `tcpwrapper`'s messages.

### 22.3.5 Advanced tcpwrapper Options

Instead of specifying a particular shell command that should be executed when a (daemon, host) line is matched, `tcpwrapper` allows you to specify a rich set of options. To use options, you compile the `tcpwrapper` program with the option -DPROCESS_OPTIONS. If you compile with -DPROCESS_OPTIONS, you must change the files /etc/hosts.allow and /etc/hosts.deny files to reflect that change; the format of these files when `tcpwrapper` is compiled with -DPROCESS_OPTIONS is incompatible with the format of the files when tcpwrapper is compiled without the options.

If you do compile with -DPROCESS_OPTIONS, the new format of the /etc/hosts.allow and /etc/hosts.deny becomes:

>     daemon_list : client_host_list : option : option ...

Because you may have more than one option on a line, if you need to place a colon (:) within the option, you must protect it with a backslash (\).

The options allow you considerable flexibility in handling a variety of conditions. They also somewhat obsolete the need to have separate /etc/hosts.allow and /etc/hosts.deny files, as the words "allow" and "deny" are now option keywords (making it possible to deny a specific pair (daemon, client) in the /etc/hosts.allow file, or vice versa). Although you should check `tcpwrapper`'s documentation for a current list of options, most of them are included in Table 22.3

Table 22.3: Advanced Options for tcpwrapper When Compiled with -DPROCESS_OPTIONS
Option | Effect
--- | ---
allow | Allows the connection.
deny | Denies the connection.
Options for dealing with sub-shells:
nice nn | Changes the priority of the process to nn. Use numbers such as +4 or +8 to reduce the amount of CPU time allocated to network services.
setenv name value | Sets the environment variable name to value for the daemon.
spawn shell_command | Runs the shell_command. The streams `stdin`, `stdout`, and `stderr` are connected to /dev/null to avoid conflict with any communications with the client.
twist shell_command | Runs the shell_command. The streams `stdin`, `stdout`, and `stderr` are connected to the remote client. This allows you to run a server process other than the one specified in the file /etc/inetd.conf. (Note: Will not work with some UDP services.)
umask nnn | Specifies the umask that should be used for sub-shells. Specify it in octal.
user username | Assume the privileges of username. (Note: `tcpwrapper` must be running as root for this option to work.)
user username.groupname | Assume the privileges of username and set the current group to be groupname.
Options for dealing with the network connection:
banners /some/directory/ | Specifies a directory that contains banner files. If a filename is found in the banner directory that has the same name as the network server (such as telnetd), the contents of the banner file are sent to the client before the TCP connection is turned over to the server. This process allows you to send clients messages, for example, informing them that unauthorized use of your computer is prohibited.
keepalive | Causes the UNIX kernel to periodically send a message to a client process; if the message cannot be sent, the connection is automatically broken.
linger seconds | Specifies how long the UNIX kernel should spend trying to send a message to the remote client after the server closes the connection.
rfc931 [timeout in seconds] | Specifies that the `ident` protocol should be used to attempt to determine the username of the person running the client program on the remote computer. The timeout, if specified, is the number of seconds that `tcpwrapper` should spend waiting for this information.

.

Don't be afraid of using these so-called "advanced" options: they actually allow you to have simpler configurations than the /etc/hosts.allow and /etc/hosts.deny files.

> NOTE: The following examples use DNS hostnames for clarity. For added security, use IP addresses instead.

Suppose you wish to allow all connections to your computer, except those from the computers in the domain pirate.net, with this very simple /etc/hosts.allow file; specify:

>     #
>     # /etc/hosts.allow:
>     #
>     # Allow anybody to connect to our machine except people from pirate.net
>     #
>     all : .pirate.net : deny
>     all : all         : allow

Suppose you wish to modify your rules to allow the use of `finger` from any of your internal machines, but you wish to have external `finger` requests met with a canned message. You might try this configuration file:

>     #
>     # /etc/hosts.allow:
>     #
>     # Allow anybody to connect to our machine except people from pirate.net
>     #
>     #
>     in.fingerd : LOCAL : allow
>     in.fingerd : all : twist /usr/local/bin/external_fingerd_message
>     all : .pirate.net : deny
>     all : all : allow

If you discover repeated break-in attempts through `telnet` and `rlogin` from all over the world, but you have a particular user who needs to telnet into your computer from the host sleepy.com, you could accomplish this somewhat more complex security requirement with the following configuration file:

>     #
>     # /etc/hosts.allow:
>     #
>     # Allow email from pirate.net, but nothing else:
>     # Allow telnet & rlogin from sleepy.com, but nowhere else
>     #
>     telnetd,rlogind : sleepy.com : allow
>     telnetd,rlogind : all : deny
>     in.fingerd : LOCAL : allow
>     in.fingerd : all : twist /usr/local/bin/external_fingerd_message
>     all : .pirate.net : deny
>     all : all : allow

Here's an example that combines two possible options:

>     #
>     # /etc/hosts.deny:
>     #
>     # Don't allow logins from pirate.net, and log attempts
>     #
>     telnetd,rlogind : pirate.net : spawn=(/security/logit %d deny %c %p %a %h %u)&\
>     : linger 10 : banners /security/banners

In the file /security/banners/telnetd, you would have the following text:

> This machine is owned and operated by the Big Whammix Corporation for the exclusive use of Big Whammix Corporation employees. Your attempt to access this machine is not allowed.

> Access to Big Whammix Corporation computers is logged and monitored. If you use or attempt to use a Big Whammix computer system, you consent to such monitoring and to adhere to Big Whammix Corporation policies about appropriate use. If you do not agree, then do not attempt use of these systems. Unauthorized use of Big Whammix Corporation computers may be in violation of state or Federal law, and will be prosecuted.

> If you have any questions about this message or policy, contact <security@bwammix.com> or call during EST business hours: 1-800-555-3662.

The banner will be displayed if anyone from pirate.net tries to log in over the net. The system will pause 10 seconds for the message to be fully displayed before disconnecting.

In the /security/logit shell file, you could have something similar to the script in Example 22.1. This script puts an entry into the `syslog` about the event, and attempts to raise a very visible alert window on the screen of the security administrator's workstation. Furthermore, it does a reverse `finger` on the calling host, and for good measure does a `netstat` and `ps` on the local machine. This process is done in the event that some mischief is already occurring that hasn't triggered an alarm.

Note the -n option to the `netstat` command in the script. This is because DNS can be slow to resolve all the IP numbers to names. You want the command to complete before the connection is dropped; it is always possible to look the hostnames up later from the log file.

#### Example 22.1: alert Script

    #!/bin/ksh

    set -o nolog -u -h +a +o bgnice +e -m

    #  Bmon is intended to capture some information about whatever site is
    #  twisting my doorknob. It is probably higher overhead than I need,
    #  but...

    export PATH=/usr/ucb:/usr/bin:/bin:/usr/etc:/etc

    mkdir /tmp/root

    # Create /tmp/root in case it doesn't exist.

    print "Subject: Notice\nFrom: operator\n\n$@" | /usr/lib/sendmail security

    typeset daemon="$1" status="$2" client="$3" pid=$4 addr=$5 host=$6 user=$7

    # For most things, we simply want a notice.
    # Unsuccessful attempts are warnings
    # Unsuccessful attempts on special accounts merit an alert

    typeset level=notice

    [[ $status != allow ]] && level=warning
    [[ $daemon = in.@(rshd|rlogind) && $user = @(root|security) ]] && level=alert

    /usr/ucb/logger -t tcpd -p auth.$level "$*" &

    umask 037

    function mktemp {
        typeset temp=/security/log.$$
        typeset -Z3 suffix=0

        while [[ -a $temp.$suffix ]]
        do
        let suffix+=1
        done

        logfile=$temp.$suffix
        chgrp security $logfile
    }

    function Indent {
        sed -e 's/^//' >> $logfile
    }

    exec 3>&1 >>$logfile 2>&1

    date
    print "Remote host: $host   Remote user: $user"

    print ""
    print "Local processes:"
    ps axg | Indent

    print ""
    print "Local network connections:"
    netstat -n -a -f inet | Indent

    print ""
    print "Finger of $host"
    safe_finger -s @$host|Indent
    print ""
    [[ $user != unknown ]] && safe_finger -h -p -m $user@$host | Indent

    exec >> /netc/log/$daemon.log 2>&1
    print "-----------------------"
    print "\npid=$pid client=$client addr=$addr user=$user"
    print Details in $logfile
    date
    print ""

    # Now bring up an alert box on the admin's workstation

    {
      print "\ndaemon=$daemon client=$client addr=$addr user=$user"
      print Details in $logfile
      date
      print ""
      print -n "(press return to close window.)" >> /tmp/root/alert.$$
    } > /tmp/root/alert.$$

    integer lines=$(wc -l < /tmp/root/alert.$$ | tr -d ' ')

    xterm -display security:0  -fg white -bg red -fn 9x15 -T "ALERT" -fn 9x15B\
       -geom 60x$lines+20+20 -e sh -c "cat /tmp/root/alert.$$;read nothing"
    /bin/rm /tmp/root/alert.$$

### 22.3.6 Making Sense of Your tcpwrapper Configuration Files

The configuration files we have shown earlier are simple; unfortunately, sometimes things get complicated. The `tcpwrapper` system comes with a utility called `tcpdchk` that will scan through your configuration file and report on a wide variety of potential configuration errors.

The `tcpwrapper` system comes with another utility program called `tcpdmatch`, which allows you to simulate an incoming connection and determine if the connection would be permitted or blocked with your current configuration files.

Programs like `tcpdchk` and `tcpdmatch` are excellent complements to the security program `tcpwrapper`, because they help you head off security problems before they happen. Wietse Venema is to be complimented for thinking to write and include them in his `tcpwrapper` release; other programmers should follow his example.

22.2 sendmail (smap/smapd) Wrapper |  | 22.4 SOCKS